package com.zhou.demo.runner;

import com.zhou.demo.enums.DelayQueueEnum;
import com.zhou.demo.hander.DelayQueueHandler;
import com.zhou.demo.utils.RedisDelayQueueUtil;
import com.zhou.demo.utils.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Redis延迟队列运行器
 * 用于在Spring Boot启动后监听各个延迟队列，并在线程池中执行对应的业务逻辑。
 *
 * @author zhouquan
 */
@Slf4j
@Component
public class RedisDelayQueueRunner implements CommandLineRunner {

    @Resource
    private RedisDelayQueueUtil redisDelayQueueUtil;

    /**
     * 线程池，用于并发监听不同的延迟队列
     */
    private final ExecutorService executorService = Executors.newCachedThreadPool();

    /**
     * 运行状态标志，控制线程是否持续监听队列
     */
    private volatile boolean running = true;

    /**
     * Spring Boot 启动完成后自动运行的方法
     * 遍历所有延迟队列枚举，为每个队列创建一个监听线程
     *
     * @param args 命令行参数
     */
    @Override
    public void run(String... args) {
        for (DelayQueueEnum queueEnum : DelayQueueEnum.values()) {
            executorService.execute(() -> {
                log.info("启动延迟队列监听线程：{}", queueEnum.getCode());
                while (running) {
                    try {
                        Object value = redisDelayQueueUtil.getDelayQueue(queueEnum.getCode());
                        DelayQueueHandler handler = SpringUtils.getBean(queueEnum.getBeanClass());
                        handler.execute(value);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        log.warn("线程中断：{}", queueEnum.getCode());
                    } catch (Exception ex) {
                        log.error("延迟队列 [{}] 处理异常：{}", queueEnum.getCode(), ex.getMessage(), ex);
                    }
                }
            });
        }
        log.info("所有 Redis 延迟队列监听启动完成");
    }

    /**
     * 在 Bean 销毁前关闭线程池，释放资源
     */
    @PreDestroy
    public void shutdown() {
        log.info("准备关闭 Redis 延迟队列监听线程池");
        running = false;
        executorService.shutdownNow();
    }
}
